+2007-06-01 Matthias Clasen <mclasen@redhat.com>
+
+ Add support for composited child windows. (#412882, Ryan Lortie)
+
+ * gdk/gdk.symbols:
+ * gdk/gdkdisplay.h:
+ * gdk/gdkinternals.h:
+ * gdk/gdkwindow.[hc]: Add gdk_display_supports_composite() and
+ gdk_window_set_composited().
+
+ * gdk/x11/gdkevents-x11.c:
+ * gdk/x11/gdkdisplay-x11.[hc]:
+ * gdk/x11/gdkwindow-x11.[hc]: X11 implementation.
+
+ * gdk/win32/gdkdisplay-win32.c:
+ * gdk/win32/gdkwindow-win32.c: Dummy win32 implementration.
+
+ * gdk/quartz/gdkdisplay-quartz.c:
+ * gdk/quartz/gdkwindow-quartz.c: Dummy Quartz implementation.
+
+ * gdk/directfb/gdkdisplay-directfb.c:
+ * gdk/directfb/gdkwindow-directfb.c: Dummy DirectFB implementation.
+
+ * tests/testgtk.c: Add a "composited window" test.
+
2007-06-01 Michael Natterer <mitch@imendio.com>
* gtk/gtkmenuitem.c (gtk_menu_item_position_menu): don't switch
+2007-06-01 Matthias Clasen <mclasen@redhat.com>
+
+ * gdk/gdk-sections.txt: Add new composited window api
+ * gdk/tmpl/windows.sgml: Add composited window example
+
2007-05-26 Matthias Clasen <mclasen@redhat.com>
* gtk/migrating*.sgml: Some cleanups
gdk_display_store_clipboard
gdk_display_supports_shapes
gdk_display_supports_input_shapes
+gdk_display_supports_composite
<SUBSECTION Standard>
GDK_DISPLAY_OBJECT
GDK_IS_DISPLAY
gdk_window_set_keep_above
gdk_window_set_keep_below
gdk_window_set_opacity
+gdk_window_set_composited
gdk_window_move
gdk_window_resize
gdk_window_move_resize
as a "window" with a titlebar and so on; a #GtkWindow may contain many #GdkWindow.
For example, each #GtkButton has a #GdkWindow associated with it.
</para>
+<example id="composited-window-example"><title>Composited windows</title>
+<programlisting><![CDATA[
+#include <gtk/gtk.h>
+
+/* The expose event handler for the event box.
+ *
+ * This function simply draws a transparency onto a widget on the area
+ * for which it receives expose events. This is intended to give the
+ * event box a "transparent" background.
+ *
+ * In order for this to work properly, the widget must have an RGBA
+ * colourmap. The widget should also be set as app-paintable since it
+ * doesn't make sense for GTK+ to draw a background if we are drawing it
+ * (and because GTK+ might actually replace our transparency with its
+ * default background colour).
+ */
+static gboolean
+transparent_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ cairo_t *cr;
+
+ cr = gdk_cairo_create (widget->window);
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ gdk_cairo_region (cr, event->region);
+ cairo_fill (cr);
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+/* The expose event handler for the window.
+ *
+ * This function performs the actual compositing of the event box onto
+ * the already-existing background of the window at 50% normal opacity.
+ *
+ * In this case we do not want app-paintable to be set on the widget
+ * since we want it to draw its own (red) background. Because of this,
+ * however, we must ensure that we use g_signal_register_after so that
+ * this handler is called after the red has been drawn. If it was
+ * called before then GTK would just blindly paint over our work.
+ *
+ * Note: if the child window has children, then you need a cairo 1.16
+ * feature to make this work correctly.
+ */
+static gboolean
+window_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GdkRegion *region;
+ GtkWidget *child;
+ cairo_t *cr;
+
+ /* get our child (in this case, the event box) */
+ child = gtk_bin_get_child (GTK_BIN (widget));
+
+ /* create a cairo context to draw to the window */
+ cr = gdk_cairo_create (widget->window);
+
+ /* the source data is the (composited) event box */
+ gdk_cairo_set_source_pixmap (cr, child->window,
+ child->allocation.x,
+ child->allocation.y);
+
+ /* draw no more than our expose event intersects our child */
+ region = gdk_region_rectangle (&child->allocation);
+ gdk_region_intersect (region, event->region);
+ gdk_cairo_region (cr, region);
+ cairo_clip (cr);
+
+ /* composite, with a 50% opacity */
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_paint_with_alpha (cr, 0.5);
+
+ /* we're done */
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+int
+main (int argc, char **argv)
+{
+ GtkWidget *window, *event, *button;
+ GdkScreen *screen;
+ GdkColormap *rgba;
+ GdkColor red;
+
+ gtk_init (&argc, &argv);
+
+ /* Make the widgets */
+ button = gtk_button_new_with_label ("A Button");
+ event = gtk_event_box_new ();
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ /* Put a red background on the window */
+ gdk_color_parse ("red", &red);
+ gtk_widget_modify_bg (window, GTK_STATE_NORMAL, &red);
+
+ /* Set the colourmap for the event box.
+ * Must be done before the event box is realised.
+ */
+ screen = gtk_widget_get_screen (event);
+ rgba = gdk_screen_get_rgba_colormap (screen);
+ gtk_widget_set_colormap (event, rgba);
+
+ /* Set our event box to have a fully-transparent background
+ * drawn on it. Currently there is no way to simply tell GTK+
+ * that "transparency" is the background colour for a widget.
+ */
+ gtk_widget_set_app_paintable (GTK_WIDGET (event), TRUE);
+ g_signal_connect (event, "expose-event",
+ G_CALLBACK (transparent_expose), NULL);
+
+ /* Put them inside one another */
+ gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+ gtk_container_add (GTK_CONTAINER (window), event);
+ gtk_container_add (GTK_CONTAINER (event), button);
+
+ /* Realise and show everything */
+ gtk_widget_show_all (window);
+
+ /* Set the event box GdkWindow to be composited.
+ * Obviously must be performed after event box is realised.
+ */
+ gdk_window_set_composited (event->window, TRUE);
+
+ /* Set up the compositing handler.
+ * Note that we do _after_ so that the normal (red) background is drawn
+ * by gtk before our compositing occurs.
+ */
+ g_signal_connect_after (window, "expose-event",
+ G_CALLBACK (window_expose_event), NULL);
+
+ gtk_main (<!-- -->);
+
+ return 0;
+}
+]]>
+</programlisting></example>
+<para>
+In the example <xref linkend="composited-window-example"/>, a button is
+placed inside of an event box inside of a window. The event box is
+set as composited and therefore is no longer automatically drawn to
+the screen.
+</para>
+<para>
+When the contents of the event box change, an expose event is
+generated on its parent window (which, in this case, belongs to
+the toplevel #GtkWindow). The expose handler for this widget is
+responsible for merging the changes back on the screen in the way
+that it wishes.
+</para>
+<para>
+In our case, we merge the contents with a 50% transparency. We
+also set the background colour of the window to red. The effect is
+that the background shows through the button.
+</para>
<!-- ##### SECTION See_Also ##### -->
<para>
@opacity:
+<!-- ##### FUNCTION gdk_window_set_composited ##### -->
+<para>
+
+</para>
+
+@window:
+@composited:
+
+
<!-- ##### FUNCTION gdk_window_move ##### -->
<para>
{
}
+
+gboolean
+gdk_display_supports_composite (GdkDisplay *display)
+{
+ return FALSE;
+}
+
#define __GDK_DISPLAY_X11_C__
#include "gdkaliasdef.c"
cardinal = opacity * 0xff;
gdk_directfb_window_set_opacity(window,cardinal);
}
+
+void
+_gdk_windowing_window_set_composited (GdkWindow *window,
+ gboolean composited)
+{
+}
+
+
#define __GDK_WINDOW_X11_C__
#include "gdkaliasdef.c"
gdk_display_supports_selection_notification
gdk_display_supports_shapes
gdk_display_supports_input_shapes
+gdk_display_supports_composite
#endif
#endif
gdk_window_set_debug_updates
gdk_window_set_user_data
gdk_window_thaw_updates
+gdk_window_set_composited
#endif
#endif
gboolean gdk_display_supports_shapes (GdkDisplay *display);
gboolean gdk_display_supports_input_shapes (GdkDisplay *display);
+gboolean gdk_display_supports_composite (GdkDisplay *display);
G_END_DECLS
void _gdk_windowing_display_set_sm_client_id (GdkDisplay *display,
const gchar *sm_client_id);
+void _gdk_windowing_window_set_composited (GdkWindow *window,
+ gboolean composited);
+
#define GDK_TYPE_PAINTABLE (_gdk_paintable_get_type ())
#define GDK_PAINTABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_PAINTABLE, GdkPaintable))
#define GDK_IS_PAINTABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_PAINTABLE))
{
#ifdef USE_BACKING_STORE
GdkWindowObject *private = (GdkWindowObject *)window;
+ GdkWindowObject *composited;
GdkWindowPaint *paint;
GdkGC *tmp_gc;
GdkRectangle clip_box;
g_object_unref (paint->pixmap);
gdk_region_destroy (paint->region);
g_free (paint);
+
+ /* find a composited window in our hierarchy to signal its
+ * parent to redraw, calculating the clip box as we go...
+ *
+ * stop if parent becomes NULL since then we'd have nowhere
+ * to draw (ie: 'composited' will always be non-NULL here).
+ */
+ for (composited = private;
+ composited->parent;
+ composited = composited->parent)
+ {
+ int width, height;
+
+ gdk_drawable_get_size (GDK_DRAWABLE (composited->parent),
+ &width, &height);
+
+ clip_box.x += composited->x;
+ clip_box.y += composited->y;
+ clip_box.width = MIN (clip_box.width, width - clip_box.x);
+ clip_box.height = MIN (clip_box.height, height - clip_box.y);
+
+ if (composited->composited)
+ {
+ gdk_window_invalidate_rect (GDK_WINDOW (composited->parent),
+ &clip_box, FALSE);
+ break;
+ }
+ }
#endif /* USE_BACKING_STORE */
}
child_region = gdk_region_rectangle (&child_rect);
/* remove child area from the invalid area of the parent */
- if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped)
+ if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped &&
+ !child->composited)
gdk_region_subtract (visible_region, child_region);
if (child_func && (*child_func) ((GdkWindow *)child, user_data))
return gdk_window_foreign_new_for_display (gdk_display_get_default (), anid);
}
+/**
+ * gdk_window_set_composited:
+ * @window: a #GdkWindow
+ *
+ * Sets a #GdkWindow as composited. Composited windows do
+ * not automatically have their contents drawn to the screen.
+ * Drawing is redirected to an offscreen buffer and an expose
+ * event is emitted on the parent of the composited window.
+ * It is the responsibility of the parent's expose handler to
+ * manually merge the off-screen content onto the screen in
+ * whatever way it sees fit. See <xref linkend="composited-window-example"/>
+ * for an example.
+ *
+ * It only makes sense for child windows to be composited; see
+ * gdk_window_set_opacity() if you need translucent toplevel
+ * windows.
+ *
+ * An additional effect of this call is that the area of this
+ * window is no longer clipped from regions marked for
+ * invalidation on its parent. Draws done on the parent
+ * window are also no longer clipped by the child.
+ *
+ * This call is only supported on some systems (currently,
+ * only X11 with new enough Xcomposite and Xdamage extensions).
+ * You must call gdk_display_supports_composite() to check if
+ * setting a window as composited is supported before
+ * attempting to do so.
+ *
+ * Since: 2.12
+ */
+void
+gdk_window_set_composited (GdkWindow *window,
+ gboolean composited)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+ GdkDisplay *display;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ composited = composited != FALSE;
+
+ if (private->composited == composited)
+ return;
+
+ display = gdk_drawable_get_display (GDK_DRAWABLE (window));
+
+ if (!gdk_display_supports_composite (display) && composited)
+ {
+ g_warning ("gdk_window_set_composited called but "
+ "compositing is not supported");
+ return;
+ }
+
+ _gdk_windowing_window_set_composited (window, composited);
+
+ private->composited = composited;
+}
+
#define __GDK_WINDOW_C__
#include "gdkaliasdef.c"
guint guffaw_gravity : 1;
guint input_only : 1;
guint modal_hint : 1;
+ guint composited : 1;
guint destroyed : 2;
*/
void gdk_window_set_child_shapes (GdkWindow *window);
+void gdk_window_set_composited (GdkWindow *window,
+ gboolean composited);
+
/*
* This routine allows you to merge (ie ADD) child shapes to your
* own window's shape keeping its current shape and ADDING the child
{
/* FIXME: Implement */
}
+
+
+gboolean
+gdk_display_supports_composite (GdkDisplay *display)
+{
+ /* FIXME: Implement */
+ return FALSE;
+}
[impl->toplevel setAlphaValue: opacity];
}
+
+void
+_gdk_windowing_window_set_composited (GdkWindow *window, gboolean composited)
+{
+}
return FALSE;
}
+
+gboolean
+gdk_display_supports_composite (GdkDisplay *display)
+{
+ return FALSE;
+}
opacity * 0xff,
LWA_ALPHA));
}
+
+void
+_gdk_windowing_window_set_composited (GdkWindow *window, gboolean composited)
+{
+}
#include <X11/extensions/shape.h>
#endif
+#ifdef HAVE_XCOMPOSITE
+#include <X11/extensions/Xcomposite.h>
+#endif
+
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+
static void gdk_display_x11_dispose (GObject *object);
static void gdk_display_x11_finalize (GObject *object);
#endif
display_x11->have_xfixes = FALSE;
+#ifdef HAVE_XCOMPOSITE
+ if (XCompositeQueryExtension (display_x11->xdisplay,
+ &ignore, &ignore))
+ display_x11->have_xcomposite = TRUE;
+ else
+#endif
+ display_x11->have_xcomposite = FALSE;
+
+#ifdef HAVE_XDAMAGE
+ if (XDamageQueryExtension (display_x11->xdisplay,
+ &display_x11->xdamage_event_base,
+ &ignore))
+ {
+ display_x11->have_xdamage = TRUE;
+
+ gdk_x11_register_standard_event_type (display,
+ display_x11->xdamage_event_base,
+ XDamageNumberEvents);
+ }
+ else
+#endif
+ display_x11->have_xdamage = FALSE;
+
display_x11->have_shapes = FALSE;
display_x11->have_input_shapes = FALSE;
#ifdef HAVE_SHAPE_EXT
return GDK_DISPLAY_X11 (display)->startup_notification_id;
}
+/**
+ * gdk_display_supports_composite:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if gdk_window_set_composited() can be used
+ * to redirect drawing on the window using compositing.
+ *
+ * Currently this only works on X11 with XComposite and
+ * XDamage extensions available.
+ *
+ * Returns: %TRUE if windows may be composited.
+ *
+ * Since: 2.12
+ */
+gboolean
+gdk_display_supports_composite (GdkDisplay *display)
+{
+ GdkDisplayX11 *x11_display = GDK_DISPLAY_X11 (display);
+
+ return x11_display->have_xcomposite &&
+ x11_display->have_xdamage &&
+ x11_display->have_xfixes;
+}
+
+
#define __GDK_DISPLAY_X11_C__
#include "gdkaliasdef.c"
gboolean have_xfixes;
gint xfixes_event_base;
+ gboolean have_xcomposite;
+ gboolean have_xdamage;
+ gint xdamage_event_base;
+
/* If the SECURITY extension is in place, whether this client holds
* a trusted authorization and so is allowed to make various requests
* (grabs, properties etc.) Otherwise always TRUE. */
}
else
#endif
+#if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
+ if (display_x11->have_xdamage && window_private->composited &&
+ xevent->type == display_x11->xdamage_event_base + XDamageNotify)
+ {
+ XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) xevent;
+ XserverRegion repair;
+ GdkRectangle rect;
+
+ rect.x = window_private->x + damage_event->area.x;
+ rect.y = window_private->y + damage_event->area.y;
+ rect.width = damage_event->area.width;
+ rect.height = damage_event->area.height;
+
+ repair = XFixesCreateRegion (display_x11->xdisplay,
+ &damage_event->area, 1);
+ XDamageSubtract (display_x11->xdisplay,
+ window_impl->damage,
+ repair, None);
+ XFixesDestroyRegion (display_x11->xdisplay, repair);
+
+ if (window_private->parent != NULL)
+ _gdk_window_process_expose (GDK_WINDOW (window_private->parent),
+ damage_event->serial, &rect);
+
+ return_val = TRUE;
+ }
+ else
+#endif
{
/* something else - (e.g., a Xinput event) */
#include <X11/extensions/shape.h>
#endif
+#ifdef HAVE_XCOMPOSITE
+#include <X11/extensions/Xcomposite.h>
+#endif
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+
const int _gdk_event_mask_table[21] =
{
ExposureMask,
_gdk_xgrab_check_destroy (GDK_WINDOW (wrapper));
+#if defined(HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
+ if (window_impl->damage != None)
+ {
+ XDamageDestroy (GDK_WINDOW_XDISPLAY (object), window_impl->damage);
+ window_impl->damage = None;
+ }
+#endif
+
if (!GDK_WINDOW_DESTROYED (wrapper))
{
GdkDisplay *display = GDK_WINDOW_DISPLAY (wrapper);
*
* Request the windowing system to make @window partially transparent,
* with opacity 0 being fully transparent and 1 fully opaque. (Values
- * of the opacity parameter are clamped to the [0,1] range.) On X11
- * this works only on X screens with a compositing manager running.
+ * of the opacity parameter are clamped to the [0,1] range.)
+ *
+ * On X11, this works only on X screens with a compositing manager
+ * running.
*
* For setting up per-pixel alpha, see gdk_screen_get_rgba_colormap().
+ * For making non-toplevel windows translucent, see
+ * gdk_window_set_composited().
*
* Since: 2.12
*/
(guchar *) cardinal, 1);
}
+void
+_gdk_windowing_window_set_composited (GdkWindow *window,
+ gboolean composited)
+{
+#if defined(HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
+ GdkWindowObject *private = (GdkWindowObject *) window;
+ GdkDisplayX11 *x11_display;
+ GdkWindowImplX11 *impl;
+ GdkDisplay *display;
+ Display *dpy;
+ Window xid;
+
+ impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
+ display = gdk_screen_get_display (GDK_DRAWABLE_IMPL_X11 (impl)->screen);
+ x11_display = GDK_DISPLAY_X11 (display);
+ dpy = GDK_DISPLAY_XDISPLAY (display);
+ xid = GDK_WINDOW_XWINDOW (private);
+
+ if (composited)
+ {
+ XCompositeRedirectWindow (dpy, xid, CompositeRedirectManual);
+ impl->damage = XDamageCreate (dpy, xid, XDamageReportBoundingBox);
+ }
+ else
+ {
+ XCompositeUnredirectWindow (dpy, xid, CompositeRedirectManual);
+ XDamageDestroy (dpy, impl->damage);
+ impl->damage = None;
+ }
+#endif
+}
+
+
#define __GDK_WINDOW_X11_C__
#include "gdkaliasdef.c"
#include <gdk/x11/gdkdrawable-x11.h>
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+
#ifdef HAVE_XSYNC
#include <X11/extensions/sync.h>
#endif
gint8 toplevel_window_type;
guint override_redirect : 1;
guint use_synchronized_configure : 1;
+
+#if defined (HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
+ Damage damage;
+#endif
};
struct _GdkWindowImplX11Class
gtk_widget_destroy (window);
}
+/*
+ * Composited non-toplevel window
+ */
+
+/* The expose event handler for the event box.
+ *
+ * This function simply draws a transparency onto a widget on the area
+ * for which it receives expose events. This is intended to give the
+ * event box a "transparent" background.
+ *
+ * In order for this to work properly, the widget must have an RGBA
+ * colourmap. The widget should also be set as app-paintable since it
+ * doesn't make sense for GTK to draw a background if we are drawing it
+ * (and because GTK might actually replace our transparency with its
+ * default background colour).
+ */
+static gboolean
+transparent_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ cairo_t *cr;
+
+ cr = gdk_cairo_create (widget->window);
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ gdk_cairo_region (cr, event->region);
+ cairo_fill (cr);
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+/* The expose event handler for the window.
+ *
+ * This function performs the actual compositing of the event box onto
+ * the already-existing background of the window at 50% normal opacity.
+ *
+ * In this case we do not want app-paintable to be set on the widget
+ * since we want it to draw its own (red) background. Because of this,
+ * however, we must ensure that we use g_signal_register_after so that
+ * this handler is called after the red has been drawn. If it was
+ * called before then GTK would just blindly paint over our work.
+ */
+static gboolean
+window_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GdkRegion *region;
+ GtkWidget *child;
+ cairo_t *cr;
+
+ /* get our child (in this case, the event box) */
+ child = gtk_bin_get_child (GTK_BIN (widget));
+
+ /* create a cairo context to draw to the window */
+ cr = gdk_cairo_create (widget->window);
+
+ /* the source data is the (composited) event box */
+ gdk_cairo_set_source_pixmap (cr, child->window,
+ child->allocation.x,
+ child->allocation.y);
+
+ /* draw no more than our expose event intersects our child */
+ region = gdk_region_rectangle (&child->allocation);
+ gdk_region_intersect (region, event->region);
+ gdk_cairo_region (cr, region);
+ cairo_clip (cr);
+
+ /* composite, with a 50% opacity */
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_paint_with_alpha (cr, 0.5);
+
+ /* we're done */
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+void
+create_composited_window (GtkWidget *widget)
+{
+ static GtkWidget *window;
+
+ if (!window)
+ {
+ GtkWidget *event, *button;
+ GdkScreen *screen;
+ GdkColormap *rgba;
+ GdkColor red;
+
+ /* make the widgets */
+ button = gtk_button_new_with_label ("A Button");
+ event = gtk_event_box_new ();
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ /* put a red background on the window */
+ gdk_color_parse ("red", &red);
+ gtk_widget_modify_bg (window, GTK_STATE_NORMAL, &red);
+
+ /* set the colourmap for the event box.
+ * must be done before the event box is realised.
+ */
+ screen = gtk_widget_get_screen (event);
+ rgba = gdk_screen_get_rgba_colormap (screen);
+ gtk_widget_set_colormap (event, rgba);
+
+ /* set our event box to have a fully-transparent background
+ * drawn on it. currently there is no way to simply tell gtk
+ * that "transparency" is the background colour for a widget.
+ */
+ gtk_widget_set_app_paintable (GTK_WIDGET (event), TRUE);
+ g_signal_connect (event, "expose-event",
+ G_CALLBACK (transparent_expose), NULL);
+
+ /* put them inside one another */
+ gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+ gtk_container_add (GTK_CONTAINER (window), event);
+ gtk_container_add (GTK_CONTAINER (event), button);
+
+ /* realise and show everything */
+ gtk_widget_realize (button);
+
+ /* set the event box GdkWindow to be composited.
+ * obviously must be performed after event box is realised.
+ */
+ gdk_window_set_composited (event->window, TRUE);
+
+ /* set up the compositing handler.
+ * note that we do _after so that the normal (red) background is drawn
+ * by gtk before our compositing occurs.
+ */
+ g_signal_connect_after (window, "expose-event",
+ G_CALLBACK (window_expose_event), NULL);
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show_all (window);
+ else
+ gtk_widget_destroy (window);
+}
+
/*
* Big windows and guffaw scrolling
*/
{ "check buttons", create_check_buttons },
{ "clist", create_clist},
{ "color selection", create_color_selection },
+ { "composited window", create_composited_window },
{ "ctree", create_ctree },
{ "cursors", create_cursors },
{ "dialog", create_dialog, TRUE },